#ifndef VECTOR_3_H
#define VECTOR_3_H

#include "../VectorX/VectorX.hpp"

namespace sMathLib
{

enum
{
	x, y, z
};

/// Assignment operators
template<>
VectorX<double, 3>& VectorX<double, 3>::operator=(const VectorX& rhs)
{
	raw_data[0] = rhs.raw_data[0];
	raw_data[1] = rhs.raw_data[1];
	raw_data[2] = rhs.raw_data[2];

	return *this;
}

template<>
VectorX<float, 3>& VectorX<float, 3>::operator=(const VectorX& rhs)
{
	raw_data[0] = rhs.raw_data[0];
	raw_data[1] = rhs.raw_data[1];
	raw_data[2] = rhs.raw_data[2];

	return *this;
}

template<>
VectorX<int, 3>& VectorX<int, 3>::operator=(const VectorX& rhs)
{
	raw_data[0] = rhs.raw_data[0];
	raw_data[1] = rhs.raw_data[1];
	raw_data[2] = rhs.raw_data[2];

	return *this;
}


template<>
VectorX<double, 3>& VectorX<double, 3>::operator+=(const VectorX& rhs)
{
	raw_data[0] += rhs.raw_data[0];
	raw_data[1] += rhs.raw_data[1];
	raw_data[2] += rhs.raw_data[2];

	return *this;
}

template<>
VectorX<float, 3>& VectorX<float, 3>::operator+=(const VectorX& rhs)
{
	raw_data[0] += rhs.raw_data[0];
	raw_data[1] += rhs.raw_data[1];
	raw_data[2] += rhs.raw_data[2];

	return *this;
}

template<>
VectorX<int, 3>& VectorX<int, 3>::operator+=(const VectorX& rhs)
{
	raw_data[0] += rhs.raw_data[0];
	raw_data[1] += rhs.raw_data[1];
	raw_data[2] += rhs.raw_data[2];

	return *this;
}


template<>
VectorX<double, 3>& VectorX<double, 3>::operator-=(const VectorX& rhs)
{
	raw_data[0] -= rhs.raw_data[0];
	raw_data[1] -= rhs.raw_data[1];
	raw_data[2] -= rhs.raw_data[2];

	return *this;
}

template<>
VectorX<float, 3>& VectorX<float, 3>::operator-=(const VectorX& rhs)
{
	raw_data[0] -= rhs.raw_data[0];
	raw_data[1] -= rhs.raw_data[1];
	raw_data[2] -= rhs.raw_data[2];

	return *this;
}

template<>
VectorX<int, 3>& VectorX<int, 3>::operator-=(const VectorX& rhs)
{
	raw_data[0] -= rhs.raw_data[0];
	raw_data[1] -= rhs.raw_data[1];
	raw_data[2] -= rhs.raw_data[2];

	return *this;
}


template<>
VectorX<double, 3>& VectorX<double, 3>::operator*=(const double& rhs)
{
	raw_data[0] *= rhs;
	raw_data[1] *= rhs;
	raw_data[2] *= rhs;
	return *this;
}

template<>
VectorX<float, 3>& VectorX<float, 3>::operator*=(const float& rhs)
{
	raw_data[0] *= rhs;
	raw_data[1] *= rhs;
	raw_data[2] *= rhs;
	return *this;
}

template<>
VectorX<int, 3>& VectorX<int, 3>::operator*=(const int& rhs)
{
	raw_data[0] *= rhs;
	raw_data[1] *= rhs;
	raw_data[2] *= rhs;
	return *this;
}

/// Explicit operators
template<>
double VectorX<double, 3>::abs() const
{
	return std::sqrt( raw_data[0]*raw_data[0] + raw_data[1]*raw_data[1] + raw_data[2]*raw_data[2] );
}

template<>
float VectorX<float, 3>::abs() const
{
	return std::sqrt( raw_data[0]*raw_data[0] + raw_data[1]*raw_data[1] + raw_data[2]*raw_data[2] );
}

template<>
double VectorX<double, 3>::volume() const
{
	return raw_data[0] * raw_data[1] * raw_data[2];
}

template<>
float VectorX<float, 3>::volume() const
{
	return raw_data[0] * raw_data[1] * raw_data[2];
}

template<>
int VectorX<int, 3>::volume() const
{
	return raw_data[0] * raw_data[1] * raw_data[2];
}


template<>
double VectorX<double, 3>::normSqr() const
{
	double ret = double();

	for(int index = 0; index != 3; ++index)
	{
		ret += raw_data[index] * raw_data[index];
	}

	return ret;
}

template<>
float VectorX<float, 3>::normSqr() const
{
	float ret = float();

	for(int index = 0; index != 3; ++index)
	{
		ret += raw_data[index] * raw_data[index];
	}

	return ret;
}

template<>
int VectorX<int, 3>::normSqr() const
{
	int ret = int();

	for(int index = 0; index != 3; ++index)
	{
		ret += raw_data[index] * raw_data[index];
	}

	return ret;
}


typedef VectorX<double, 3> Vector3;

/// Cross production
Vector3 cross(const Vector3& lhs, const Vector3& rhs)
{
	Vector3 ret
		( (lhs[1] * rhs[2] - lhs[2] * rhs[1]),
		  (lhs[2] * rhs[0] - lhs[0] * rhs[2]),
		  (lhs[0] * rhs[1] - lhs[1] * rhs[0])
		);
	return ret;
}

} // namespace sMathLib

#endif // VECTOR_3_H
